#include <QSerialPortInfo>
#include <QMessageBox>
#include <QDebug>

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include "counter_cmd.h"
#include "print_cmd.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
    , m_portscan_timer()
    , m_portdata_timer()
    , m_data_received()
{
    ui->setupUi(this);

    initSerialPort();
    updateOpenButtonState();

//    prtr_init();
//    prtr_command(0);
}

MainWindow::~MainWindow()
{
    prtr_deinit();
    if (m_port)
        closeSerialPort();

    delete ui;
}

void MainWindow::on_pushButton_Connect_clicked()
{
    if (m_port == nullptr) {
        if (openSerialPort()) {
            ui->pushButton_Connect->setText(tr("Disconnect"));
            setUiState(Opened);
        }
    }
    else {
        closeSerialPort();
        ui->pushButton_Connect->setText(tr("Open"));

        setUiState(Stopped);
    }
}

void MainWindow::initSerialPort()
{
    // connect the slots with their respective slots
    connect(&m_portscan_timer, SIGNAL(timeout()), this, SLOT(serialPortScan()));
    connect(&m_portdata_timer, SIGNAL(timeout()), this, SLOT(serialPortRead()));

    // start serial port detecting timer
    m_port = nullptr;
    m_serial_port_closed = true;
    m_portscan_timer.setInterval(1000);
    m_portscan_timer.start();
    m_portdata_timer.setInterval(100);
    m_portdata_timer.start();

    setUiState(Stopped);
}

void MainWindow::serialPortScan()
{
    // fetch available serial ports in the system
    const auto infos = QSerialPortInfo::availablePorts();
    // add the new serial ports' name to the comboBox list
    for (const QSerialPortInfo &info : infos) {
        if (info.hasVendorIdentifier() && ui->comboBox_SerialPort->findText(info.portName()) == -1)
            ui->comboBox_SerialPort->addItem(info.portName());
    }

    for (int k = 0; k < ui->comboBox_SerialPort->count(); k++) {
        // for each port name in comboBox
        QString s = ui->comboBox_SerialPort->itemText(k);
        bool valid = false;
        for (const QSerialPortInfo &info : infos)
            if (info.portName() == s) {
                if (!info.hasVendorIdentifier())
                    break;
                valid = true;
                break;
            }
        if (!valid) {
            // if it is not existed in the system
            if (ui->comboBox_SerialPort->currentIndex() == k && m_port) {
                // stop the current action on this port if it is open
                m_serial_port_closed = true;
                emit ui->pushButton_Connect->clicked();
            }
            // delete it from the comboBox list
            ui->comboBox_SerialPort->removeItem(k);
            k--;
        }
    }

    updateOpenButtonState();
}

void MainWindow::serialPortRead()
{
    if (m_port == nullptr)
        return;

    QByteArray ba = m_port->readAll();
    if (ba.length() == 0)
        return;
    QString data_s;
    foreach(unsigned char data_byte, ba)
        data_s += QString("%1 ").arg((unsigned int) data_byte, 2, 16, QLatin1Char('0'));
    ui->textEdit_received->append(data_s);

    m_data_received += ba;
    m_data_received = cntr_parse_response(m_data_received);
}

void MainWindow::serialPortWriteCommand(QByteArray cmd)
{
    QString data_s;
    foreach(unsigned char data_byte, cmd)
        data_s += QString("%1 ").arg((unsigned int) data_byte, 2, 16, QLatin1Char('0'));
    ui->textEdit_sent->append(data_s);

    m_last_command = cmd;
    m_port->write(cmd);
}

void MainWindow::updateOpenButtonState()
{
    if (m_port)
        return;

    bool enable = true;
    if (enable && ui->comboBox_SerialPort->count() == 0)
        enable = false;
    ui->pushButton_Connect->setEnabled(enable);
}

bool MainWindow::openSerialPort()
{
    if (m_port)
        return true;

    // create and open serial port
    m_port = new QSerialPort();
    if (!m_port)
        return false;
    m_port->setPortName(ui->comboBox_SerialPort->currentText());
    m_port->setBaudRate(QSerialPort::Baud115200);
    m_port->setDataBits(QSerialPort::Data8);
    m_port->setParity(QSerialPort::NoParity);
    m_port->setStopBits(QSerialPort::OneStop);
    m_port->setReadBufferSize(16 * 1024);
    if (!m_port->open(QIODevice::ReadWrite)) {
        delete m_port;
        m_port = nullptr;
        QMessageBox::information(this, tr("Notice"), tr("Open Serial Port Failed!"));
        return false;
    }
    
    m_serial_port_closed = false;
    ui->comboBox_SerialPort->setEnabled(false);

    return true;
}

void MainWindow::closeSerialPort()
{
    if (m_port) {
        m_port->close();
        delete m_port;
        m_port = nullptr;
    }

    ui->comboBox_SerialPort->setEnabled(true);
}

void MainWindow::setUiState(State state)
{
    if (state == Stopped) {
        ui->comboBox_SerialPort->setEnabled(true);
        ui->pushButton_Connect->setText(tr("Connect"));
        ui->frame_Control->setEnabled(false);
    }
    else if (state == Opened) {
        ui->comboBox_SerialPort->setEnabled(false);
        ui->frame_Control->setEnabled(true);
    }
}

void MainWindow::on_pushButton_CommTest_clicked()
{
    serialPortWriteCommand(cntr_pack_command(CNTR_COMM_TEST_CMD));
}

void MainWindow::on_pushButton_ClearFault_clicked()
{
    serialPortWriteCommand(cntr_pack_command(CNTR_FAULT_CLEAR_CMD));
}

void MainWindow::on_pushButton_ClearCountInfo_clicked()
{
    serialPortWriteCommand(cntr_pack_command(CNTR_CLEAR_TRANSACTION_CMD));
}

void MainWindow::on_pushButton_EnterMode_clicked()
{
    serialPortWriteCommand(cntr_pack_command(CNTR_ENTER_WORK_MODE_CMD));
}

void MainWindow::on_pushButton_ExitMode_clicked()
{
    serialPortWriteCommand(cntr_pack_command(CNTR_EXIT_WORK_MODE_CMD));
}

void MainWindow::on_pushButton_StartCount_clicked()
{
    serialPortWriteCommand(cntr_pack_command(CNTR_START_COUNT_CMD));
}

void MainWindow::on_pushButton_PauseCount_clicked()
{
    serialPortWriteCommand(cntr_pack_command(CNTR_PAUSE_COUNT_CMD));
}

void MainWindow::on_pushButton_StartStore_clicked()
{
    serialPortWriteCommand(cntr_pack_command(CNTR_STORE_NOTE_CMD));
}

void MainWindow::on_pushButton_CompleteStore_clicked()
{
    serialPortWriteCommand(cntr_pack_command(CNTR_COMPLET_STORE_NOTE_CMD));
}

void MainWindow::on_pushButton_OpenShell_clicked()
{
    serialPortWriteCommand(cntr_pack_command(CNTR_OPEN_SHELL_CMD));
}

void MainWindow::on_pushButton_CloseShell_clicked()
{
    serialPortWriteCommand(cntr_pack_command(CNTR_CLOSE_SHELL_CMD));
}

void MainWindow::on_pushButton_EnterCoinMode_clicked()
{
    serialPortWriteCommand(cntr_pack_command(CNTR_ENTER_COIN_MODE_CMD));
}

void MainWindow::on_pushButton_ExitCoinMode_clicked()
{
    serialPortWriteCommand(cntr_pack_command(CNTR_EXIT_COIN_MODE_CMD));
}

void MainWindow::on_pushButton_IntelligentMode_clicked()
{
    serialPortWriteCommand(cntr_pack_command(CNTR_MODE_SELECT, 0x01));
}

void MainWindow::on_pushButton_MixedMode_clicked()
{
    serialPortWriteCommand(cntr_pack_command(CNTR_MODE_SELECT, 0x02));
}

void MainWindow::on_pushButton_CountMode_clicked()
{
    serialPortWriteCommand(cntr_pack_command(CNTR_ENTER_WORK_MODE_CMD));
    serialPortWriteCommand(cntr_pack_command(CNTR_MODE_SELECT, 0x03));
}

